class Color {
  public static readonly RED = '#FF0000'
  public static readonly GREEN = '#00FF00'
  public static readonly BLUE = '#0000FF'

  /**
   * 静态方法，判断颜色字符串是否为16进制颜色
   * @param color 颜色字符串
   * @returns
   */
  static isHex(color: string) {
    // 使用正则表达式判断颜色字符串是否符合16进制颜色格式
    return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color)
  }

  /**
   * 将RGB颜色转换为十六进制颜色
   * @param r
   * @param g
   * @param b
   * @returns
   */
  static rgbToHex(r: number, g: number, b: number) {
    // 将RGB颜色转换为十六进制颜色
    const hex = ((r << 16) | (g << 8) | b).toString(16)
    // 返回十六进制颜色，不足6位前面补0
    return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex
  }

  /**
   *  静态方法，将16进制颜色值转换为RGB颜色值
   * @param hex 16进制颜色
   * @returns
   */
  static hexToRGB(hex: string) {
    // 将16进制颜色值转换为小写
    let sHex = hex.toLowerCase()
    // 判断传入的字符串是否为16进制颜色值
    if (this.isHex(hex)) {
      // 如果传入的字符串长度为4，则将其转换为6位16进制颜色值
      if (sHex.length === 4) {
        let sColorNew = '#'
        for (let i = 1; i < 4; i += 1) {
          sColorNew += sHex.slice(i, i + 1).concat(sHex.slice(i, i + 1))
        }
        sHex = sColorNew
      }
      // 将6位16进制颜色值转换为RGB颜色值
      const sColorChange: number[] = []
      for (let i = 1; i < 7; i += 2) {
        sColorChange.push(parseInt('0x' + sHex.slice(i, i + 2)))
      }
      // 返回RGB颜色值
      return 'RGB(' + sColorChange.join(',') + ')'
    }
    // 如果传入的字符串不是16进制颜色值，则返回原字符串
    return sHex
  }

  /**
   * 是否为深色
   * @param color 颜色字符串
   * @returns
   */
  static isDark(color: string) {
    // 判断传入的颜色是否为十六进制颜色
    if (!this.isHex(color)) return
    // 将十六进制颜色转换为RGB颜色
    const [r, g, b] = this.hexToRGB(color)
      // 去除字符串中的括号、rgb、RGB等字符
      .replace(/(?:\(|\)|rgb|RGB)*/g, '')
      // 将字符串按逗号分隔，并转换为数字
      .split(',')
      .map((item) => Number(item))
    // 根据人眼对颜色的敏感度，判断颜色是否为暗色
    return r * 0.299 + g * 0.578 + b * 0.114 < 192
  }

  /**
   * 静态方法，用于将颜色变暗
   * @param color 颜色字符串
   * @param amount
   * @returns
   */
  static darken(color: string, amount: number) {
    // 如果颜色字符串中包含#，则去掉#号
    color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color
    // 计算变暗的数值
    amount = Math.trunc((255 * amount) / 100)
    // 返回变暗后的颜色字符串
    return `#${this.subtractLight(color.substring(0, 2), amount)}${this.subtractLight(
      color.substring(2, 4),
      amount
    )}${this.subtractLight(color.substring(4, 6), amount)}`
  }

  /**
   * 静态方法，用于将颜色变亮
   * @param color 颜色字符串
   * @param amount
   * @returns
   */
  static lighten(color: string, amount: number) {
    // 如果颜色字符串中包含#，则去掉#号
    color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color
    // 计算变亮的程度
    amount = Math.trunc((255 * amount) / 100)
    // 返回变亮后的颜色字符串
    return `#${this.addLight(color.substring(0, 2), amount)}${this.addLight(
      color.substring(2, 4),
      amount
    )}${this.addLight(color.substring(4, 6), amount)}`
  }

  /**
   * 静态方法，用于增加颜色的亮度
   * @param color 颜色字符串
   * @param amount
   * @returns
   */
  static addLight(color: string, amount: number) {
    // 将颜色字符串转换为16进制数，并加上亮度值
    const cc = parseInt(color, 16) + amount
    // 如果亮度值大于255，则将其设置为255
    const c = cc > 255 ? 255 : cc
    // 将亮度值转换为16进制字符串，如果长度大于1，则直接返回，否则在前面加0
    return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`
  }

  /**
   * 静态方法，用于减少颜色的亮度
   * @param color 颜色字符串
   * @param amount
   * @returns
   */
  static subtractLight(color: string, amount: number) {
    // 将颜色字符串转换为16进制数，并减去amount
    const cc = parseInt(color, 16) - amount
    // 如果结果小于0，则将结果设为0
    const c = cc < 0 ? 0 : cc
    // 将结果转换为16进制字符串，如果长度大于1，则直接返回，否则在前面加0
    return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`
  }

  /**
   * 静态方法，计算两个RGB颜色之间的对比度
   * @param rgb1
   * @param rgb2
   * @returns
   */
  static contrast(rgb1: string[], rgb2: number[]) {
    return (
      (this.luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) /
      (this.luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05)
    )
  }

  /**
   * 静态方法，计算颜色的亮度
   * @param r 红色值
   * @param g 绿色值
   * @param b
   * @returns
   */
  static luminanace(r: number, g: number, b: number) {
    // 将rgb值除以255，得到0-1之间的值
    const a = [r, g, b].map((v) => {
      v /= 255
      // 如果值小于等于0.03928，则除以12.92，否则将值加0.055后除以1.055，再开2.4次方
      return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4)
    })
    // 返回亮度值，根据公式计算
    return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722
  }

  /**
   * 静态方法，计算最佳文本颜色
   * @param hexColor 十六进制颜色值
   * @returns
   */
  static calculateBestTextColor(hexColor: string) {
    // 将传入的十六进制颜色值转换为RGB颜色值
    const rgbColor = this.hexToRGB(hexColor.substring(1))
    // 计算RGB颜色值与黑色（[0, 0, 0]）的对比度
    const contrastWithBlack = this.contrast(rgbColor.split(','), [0, 0, 0])
    // 如果对比度大于等于12，则返回黑色（#000000），否则返回白色（#FFFFFF）
    return contrastWithBlack >= 12 ? '#000000' : '#FFFFFF'
  }
}

export default Color
